using System;
using System.Collections;
using System.Collections.Generic;
//
// DotNetNuke - http://www.dotnetnuke.com
// Copyright (c) 2002-2010
// by DotNetNuke Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//

using System.Text.RegularExpressions;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.Localization;

namespace DotNetNuke.Web.UI
{

    public class RibbonBarManager
    {

        public static DotNetNuke.Entities.Tabs.TabInfo InitTabInfoObject()
        {
            return InitTabInfoObject(null, TabRelativeLocation.AFTER);
        }

        public static DotNetNuke.Entities.Tabs.TabInfo InitTabInfoObject(DotNetNuke.Entities.Tabs.TabInfo relativeToTab)
        {
            return InitTabInfoObject(relativeToTab, TabRelativeLocation.AFTER);
        }

        public static DotNetNuke.Entities.Tabs.TabInfo InitTabInfoObject(DotNetNuke.Entities.Tabs.TabInfo relativeToTab, TabRelativeLocation location)
        {
            TabController tabCtrl = new TabController();
            if (((relativeToTab == null)))
            {
                if (((PortalSettings.Current != null) && (PortalSettings.Current.ActiveTab != null)))
                {
                    relativeToTab = PortalSettings.Current.ActiveTab;
                }
            }

            DotNetNuke.Entities.Tabs.TabInfo newTab = new DotNetNuke.Entities.Tabs.TabInfo();
            newTab.TabID = Null.NullInteger;
            newTab.TabName = "";
            newTab.Title = "";
            newTab.IsVisible = false;
            newTab.DisableLink = false;
            newTab.IsDeleted = false;
            newTab.IsSecure = false;
            newTab.PermanentRedirect = false;

            DotNetNuke.Entities.Tabs.TabInfo parentTab = GetParentTab(relativeToTab, location);

            if (((parentTab != null)))
            {
                newTab.PortalID = parentTab.PortalID;
                newTab.ParentId = parentTab.TabID;
                newTab.Level = parentTab.Level + 1;
                if ((PortalSettings.Current.SSLEnabled))
                {
                    newTab.IsSecure = parentTab.IsSecure;
                    //Inherit from parent
                }
            }
            else
            {
                newTab.PortalID = PortalSettings.Current.PortalId;
                newTab.ParentId = Null.NullInteger;
                newTab.Level = 0;
            }

            //Inherit permissions from parent
            newTab.TabPermissions.Clear();
            if ((newTab.PortalID != Null.NullInteger && (parentTab != null)))
            {
                newTab.TabPermissions.AddRange(parentTab.TabPermissions);
            }
            else if ((newTab.PortalID != Null.NullInteger))
            {
                //Give admin full permission
                ArrayList permissions = DotNetNuke.Security.Permissions.PermissionController.GetPermissionsByTab();

                foreach (DotNetNuke.Security.Permissions.PermissionInfo permission in permissions)
                {
                    DotNetNuke.Security.Permissions.TabPermissionInfo newTabPermission = new DotNetNuke.Security.Permissions.TabPermissionInfo();
                    newTabPermission.PermissionID = permission.PermissionID;
                    newTabPermission.PermissionKey = permission.PermissionKey;
                    newTabPermission.PermissionName = permission.PermissionName;
                    newTabPermission.AllowAccess = true;
                    newTabPermission.RoleID = PortalSettings.Current.AdministratorRoleId;
                    newTab.TabPermissions.Add(newTabPermission);
                }
            }

            return newTab;
        }

        public static TabInfo GetParentTab(DotNetNuke.Entities.Tabs.TabInfo relativeToTab, TabRelativeLocation location)
        {
            if (((relativeToTab == null)))
            {
                return null;
            }

            TabController tabCtrl = new TabController();
            DotNetNuke.Entities.Tabs.TabInfo parentTab = null;
            if ((location == TabRelativeLocation.CHILD))
            {
                parentTab = relativeToTab;
            }
            else if (((relativeToTab != null) && relativeToTab.ParentId != Null.NullInteger))
            {
                parentTab = tabCtrl.GetTab(relativeToTab.ParentId, relativeToTab.PortalID, false);
            }

            return parentTab;
        }

        public static IList<DotNetNuke.Entities.Tabs.TabInfo> GetPagesList()
        {
            IList<DotNetNuke.Entities.Tabs.TabInfo> portalTabs = null;
            DotNetNuke.Entities.Users.UserInfo userInfo = DotNetNuke.Entities.Users.UserController.GetCurrentUserInfo();
            if (((userInfo != null) && userInfo.UserID != Null.NullInteger))
            {
                TabController tabCtrl = new TabController();
                if ((userInfo.IsSuperUser && PortalSettings.Current.ActiveTab.IsSuperTab))
                {
                    portalTabs = tabCtrl.GetTabsByPortal(Null.NullInteger).AsList();
                }
                else
                {
                    portalTabs = TabController.GetPortalTabs(PortalSettings.Current.PortalId, Null.NullInteger, false, Null.NullString, true, false, true, false, true);
                }
            }

            if (((portalTabs == null)))
            {
                portalTabs = new List<DotNetNuke.Entities.Tabs.TabInfo>();
            }

            return portalTabs;
        }

        public static bool IsHostConsolePage()
        {
            return (PortalSettings.Current.ActiveTab.IsSuperTab && PortalSettings.Current.ActiveTab.TabPath == "//Host");
        }

        public static bool IsHostConsolePage(TabInfo tab)
        {
            return (tab.IsSuperTab && tab.TabPath == "//Host");
        }

        public static bool CanMovePage()
        {
            //Cannot move the host console page
            if ((IsHostConsolePage()))
            {
                return false;
            }

            //Page Editors - Can only move children they have 'Manage' permission to, they cannot move the top level page
            if ((!DotNetNuke.Security.PortalSecurity.IsInRole("Administrators")))
            {
                int parentTabID = PortalSettings.Current.ActiveTab.ParentId;
                if ((parentTabID == Null.NullInteger))
                {
                    return false;
                }

                TabInfo parentTab = new TabController().GetTab(parentTabID, PortalSettings.Current.ActiveTab.PortalID, false);
                string permissionList = "MANAGE";
                if ((!DotNetNuke.Security.Permissions.TabPermissionController.HasTabPermission(parentTab.TabPermissions, permissionList)))
                {
                    return false;
                }
            }

            return true;
        }

        //todo: Settings
        //Public Function SaveTabInfoObject(ByVal newTab As DotNetNuke.Entities.Tabs.TabInfo, ByVal relativeToTab As DotNetNuke.Entities.Tabs.TabInfo, ByVal location As TabRelativeLocation, ByVal templateMapPath As String, ByVal tabSettings As Hashtable) As Integer
        public static int SaveTabInfoObject(DotNetNuke.Entities.Tabs.TabInfo tab, DotNetNuke.Entities.Tabs.TabInfo relativeToTab, TabRelativeLocation location, string templateMapPath)
		{
			TabController tabCtrl = new TabController();

			//Validation:
			//Tab name is required
			//Tab name is invalid
			if ((tab.TabName == string.Empty)) {
				throw new DotNetNukeException("Page name is required.", DotNetNukeErrorCode.PageNameRequired);
			} else if ((Regex.IsMatch(tab.TabName, "^AUX$|^CON$|^LPT[1-9]$|^CON$|^COM[1-9]$|^NUL$|^SITEMAP$|^LINKCLICK$|^KEEPALIVE$|^DEFAULT$|^ERRORPAGE$", RegexOptions.IgnoreCase))) {
				throw new DotNetNukeException("Page name is invalid.", DotNetNukeErrorCode.PageNameInvalid);
			} else if ((Validate_IsCircularReference(tab.PortalID, tab.TabID))) {
				throw new DotNetNukeException("Cannot move page to that location.", DotNetNukeErrorCode.PageCircularReference);
			}

            bool usingDefaultLanguage = (tab.CultureCode == PortalSettings.Current.DefaultLanguage) || tab.CultureCode == null;

            if (PortalSettings.Current.ContentLocalizationEnabled) {
	            if ((!usingDefaultLanguage)) {
		            DotNetNuke.Entities.Tabs.TabInfo defaultLanguageSelectedTab = tab.DefaultLanguageTab;

		            if ((defaultLanguageSelectedTab == null)) {
			            //get the siblings from the selectedtab and iterate through until you find a sibbling with a corresponding defaultlanguagetab
			            //if none are found get a list of all the tabs from the default language and then select the last one
			            List<TabInfo> selectedTabSibblings = tabCtrl.GetTabsByPortal(tab.PortalID).WithCulture(tab.CultureCode, true).AsList();
			            foreach (var sibling in selectedTabSibblings) {
				            TabInfo siblingDefaultTab = sibling.DefaultLanguageTab;
				            if (((siblingDefaultTab != null))) {
					            defaultLanguageSelectedTab = siblingDefaultTab;
					            break;
				            }
			            }

			            //still haven't found it
			            if ((defaultLanguageSelectedTab == null)) {
				            List<TabInfo> defaultLanguageTabs = tabCtrl.GetTabsByPortal(tab.PortalID).WithCulture(PortalSettings.Current.DefaultLanguage, true).AsList();
				            defaultLanguageSelectedTab = defaultLanguageTabs[defaultLanguageTabs.Count];
				            //get the last tab
			            }

		            }

		            relativeToTab = defaultLanguageSelectedTab;
	            }
            }


			if ((location != TabRelativeLocation.NOTSET)) {
				//Check Host tab - don't allow adding before or after
				if ((IsHostConsolePage(relativeToTab) && (location == TabRelativeLocation.AFTER || location == TabRelativeLocation.BEFORE))) {
					throw new DotNetNukeException("You cannot add or move pages before or after the Host tab.", DotNetNukeErrorCode.HostBeforeAfterError);
				}

				DotNetNuke.Entities.Tabs.TabInfo parentTab = GetParentTab(relativeToTab, location);
				string permissionList = "ADD,COPY,EDIT,MANAGE";
				//Check permissions for Page Editors when moving or inserting
				if ((!DotNetNuke.Security.PortalSecurity.IsInRole("Administrators"))) {
					if (((parentTab == null) || !DotNetNuke.Security.Permissions.TabPermissionController.HasTabPermission(parentTab.TabPermissions, permissionList))) {
						throw new DotNetNukeException("You do not have permissions to add or move pages to this location. You can only add or move pages as children of pages you can edit.", DotNetNukeErrorCode.PageEditorPermissionError);
					}
				}

				if (((parentTab != null))) {
					tab.ParentId = parentTab.TabID;
					tab.Level = parentTab.Level + 1;
				} else {
					tab.ParentId = Null.NullInteger;
					tab.Level = 0;
				}
			}

			if ((tab.TabID > Null.NullInteger && tab.TabID == tab.ParentId)) {
				throw new DotNetNukeException("Parent page is invalid.", DotNetNukeErrorCode.ParentTabInvalid);
			}

			tab.TabPath = DotNetNuke.Common.Globals.GenerateTabPath(tab.ParentId, tab.TabName);

			try {
				if ((tab.TabID < 0)) {
					if ((tab.TabPermissions.Count == 0 && tab.PortalID != Null.NullInteger)) {
						//Give admin full permission
						ArrayList permissions = DotNetNuke.Security.Permissions.PermissionController.GetPermissionsByTab();

						foreach (DotNetNuke.Security.Permissions.PermissionInfo permission in permissions) {
							DotNetNuke.Security.Permissions.TabPermissionInfo newTabPermission = new DotNetNuke.Security.Permissions.TabPermissionInfo();
							newTabPermission.PermissionID = permission.PermissionID;
							newTabPermission.PermissionKey = permission.PermissionKey;
							newTabPermission.PermissionName = permission.PermissionName;
							newTabPermission.AllowAccess = true;
							newTabPermission.RoleID = PortalSettings.Current.AdministratorRoleId;
							tab.TabPermissions.Add(newTabPermission);
						}
					}

				    PortalSettings _PortalSettings = PortalController.GetCurrentPortalSettings();

                    if( _PortalSettings.ContentLocalizationEnabled)
                    {
                        Locale defaultLocale = LocaleController.Instance.GetDefaultLocale(tab.PortalID);
                        tab.CultureCode = defaultLocale.Code;
                    }
                    else
                    {
                        tab.CultureCode = Null.NullString;
                    }

					if ((location == TabRelativeLocation.AFTER && (relativeToTab != null))) {
						tab.TabID = tabCtrl.AddTabAfter(tab, relativeToTab.TabID);
					} else if ((location == TabRelativeLocation.BEFORE && (relativeToTab != null))) {
						tab.TabID = tabCtrl.AddTabBefore(tab, relativeToTab.TabID);
					} else {
						tab.TabID = tabCtrl.AddTab(tab);
					}

                    if(_PortalSettings.ContentLocalizationEnabled)
                    {
                        tabCtrl.CreateLocalizedCopies(tab);
                    }

				    tabCtrl.UpdateTabSetting(tab.TabID, "CacheProvider", "");
					tabCtrl.UpdateTabSetting(tab.TabID, "CacheDuration", "");
					tabCtrl.UpdateTabSetting(tab.TabID, "CacheIncludeExclude", "0");
					tabCtrl.UpdateTabSetting(tab.TabID, "IncludeVaryBy", "");
					tabCtrl.UpdateTabSetting(tab.TabID, "ExcludeVaryBy", "");
					tabCtrl.UpdateTabSetting(tab.TabID, "MaxVaryByCount", "");
				} else {
					tabCtrl.UpdateTab(tab);

					if ((location == TabRelativeLocation.AFTER && (relativeToTab != null))) {
						tabCtrl.MoveTabAfter(tab, relativeToTab.TabID);
					} else if ((location == TabRelativeLocation.BEFORE && (relativeToTab != null))) {
						tabCtrl.MoveTabBefore(tab, relativeToTab.TabID);
					}
				}
			} catch (Exception ex) {
				if ((ex.Message == "Tab Exists")) {
					throw new DotNetNukeException("Page already exists.", DotNetNukeErrorCode.PageExists);
				}
			}

			// create the page from a template
			if ((!string.IsNullOrEmpty(templateMapPath))) {
				System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
				try {
					xmlDoc.Load(templateMapPath);
					TabController.DeserializePanes(xmlDoc.SelectSingleNode("//portal/tabs/tab/panes"), tab.PortalID, tab.TabID, DotNetNuke.Entities.Portals.PortalTemplateModuleAction.Ignore, new Hashtable());
				} catch (Exception ex) {
					Exceptions.LogException(ex);
					throw new DotNetNukeException("Unable to process page template.", ex, DotNetNukeErrorCode.DeserializePanesFailed);
				}
			}

			//todo: reload tab from db or send back tabid instead?
			return tab.TabID;
		}

        public static bool Validate_IsCircularReference(int portalID, int tabID)
        {
            if (tabID != -1)
            {
                TabController objTabs = new TabController();
                TabInfo objtab = objTabs.GetTab(tabID, portalID, false);

                if (((objtab == null)))
                {
                    return false;
                }
                else if (objtab.Level == 0)
                {
                    return false;
                }
                else
                {
                    if (tabID == objtab.ParentId)
                    {
                        return true;
                    }
                    else
                    {
                        return Validate_IsCircularReference(portalID, objtab.ParentId);
                    }
                }
            }
            else
            {
                return false;
            }
        }

    }

    public class DotNetNukeException : System.Exception
    {
        public DotNetNukeException()
            : base()
        {
        }

        public DotNetNukeException(string message)
            : base(message)
        {
        }

        public DotNetNukeException(string message, System.Exception innerException)
            : base(message, innerException)
        {
        }

        public DotNetNukeException(string message, DotNetNukeErrorCode errorCode)
            : base(message)
        {
            _ErrorCode = errorCode;
        }

        public DotNetNukeException(string message, System.Exception innerException, DotNetNukeErrorCode errorCode)
            : base(message, innerException)
        {
            _ErrorCode = errorCode;
        }

        public DotNetNukeException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
            : base(info, context)
        {
        }

        private DotNetNukeErrorCode _ErrorCode = DotNetNukeErrorCode.NotSet;
        public DotNetNukeErrorCode ErrorCode
        {
            get { return _ErrorCode; }
        }
    }

    public enum DotNetNukeErrorCode
    {
        NotSet,
        PageExists,
        PageNameRequired,
        PageNameInvalid,
        DeserializePanesFailed,
        PageCircularReference,
        ParentTabInvalid,
        PageEditorPermissionError,
        HostBeforeAfterError
    }

    public enum TabRelativeLocation
    {
        NOTSET,
        BEFORE,
        AFTER,
        CHILD
    }

}

